/*
 * Copyright (C) 2011 Kamran Zafar
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * 
 * */
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Reflection;

namespace org.kamranzafar.hotfusion.gui
{
	public partial class MainForm : Form
	{
		BindingList<IconFileInfo> files = new BindingList<IconFileInfo>();
		Settings extractorSettings = null;

		public MainForm()
		{
			InitializeComponent();

			dataGridView1.AutoGenerateColumns = false;
			dataGridView1.DataSource = files;
			
			init();
		}
		
		private void init(){
			extractorSettings=new Settings();
			extractorSettings.IconFile=Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "stub.ico");
			extractorSettings.MeltOnExtract=false;
			extractorSettings.PasswordProtect=false;
			extractorSettings.HiddenExtractor=true;
			extractorSettings.ExtractorSign=new Settings.ExtractorSignature();
			extractorSettings.ExtractorSign.Type=1;
			extractorSettings.ExtractorSign.CompanyName=Application.CompanyName;
			extractorSettings.ExtractorSign.ProductName=Application.ProductVersion;
			extractorSettings.ExtractorSign.ProductVersion=Application.ProductVersion;
		}

		private void Form1_DragEnter(object sender, DragEventArgs e)
		{
			if (e.Data.GetDataPresent(DataFormats.FileDrop))
				e.Effect = DragDropEffects.Copy;
		}

		private void Form1_DragDrop(object sender, DragEventArgs e)
		{
			foreach (string filename in (string[])e.Data.GetData(DataFormats.FileDrop))
			{
				BindEntry be=new BindEntry();
				be.FilesEntry=new BindEntry.FileEntry();
				be.FilesEntry.FileName=filename;
				be.Type=1;
				
				files.Add(new IconFileInfo(be));
			}
		}
		
		private void build(bool newBuild){
			if (files.Count <= 0)
				return;
			
			Settings s=null;
			
			if(newBuild){
				SettingsForm sf = new SettingsForm(null);
				sf.ShowDialog(this);

				s=sf.getExtractorSettings();
			}else{
				s=extractorSettings;
			}
			
			if (s != null)
			{
				if (DialogResult.OK != saveFileDialog1.ShowDialog(this))
					return;

				Thread binderThread = new Thread(new ParameterizedThreadStart(bind));
				binderThread.Start(s);
			}
		}

		private void bind(object s) {
			try
			{
				using (Binder archive = new Binder((Settings)s))
				{
					foreach (IconFileInfo file in files)
					{
						archive.AddFile(file.BindEntrySetting);
					}
					archive.CompileArchive(saveFileDialog1.FileName);
				}

				MessageBox.Show(null, Path.GetFileName(saveFileDialog1.FileName) + " built successfully.",
				                Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
			}
			catch (Exception ex)
			{
				MessageBox.Show(null, ex.Message, Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}
		
		private void addFile(){
			FileSettingsForm fsf = new FileSettingsForm(null);
			fsf.ShowDialog(this);


			if(fsf.getFileSettings()!=null){
				BindEntry be=new BindEntry();
				be.FilesEntry=fsf.getFileSettings();
				be.Type=1;
				files.Add(new IconFileInfo(be));
			}
		}

		private void removeFile() {
			if (dataGridView1.SelectedRows.Count > 0)
			{
				files.RemoveAt(dataGridView1.SelectedRows[0].Index);
			}
		}

		private void dataGridView1_DoubleClick(object sender, EventArgs e)
		{
			updateFileSettings();
		}

		private void updateFileSettings() {
			if (dataGridView1.SelectedRows.Count > 0)
			{
				int index = dataGridView1.SelectedRows[0].Index;
				
				BindEntry be=files[index].BindEntrySetting;
				BindEntry newBe=new BindEntry();
				
				if(be.Type==1){
					FileSettingsForm fsf = new FileSettingsForm(files[index].BindEntrySetting.FilesEntry);
					fsf.ShowDialog(this);

					if (fsf.getFileSettings() != null)
					{
						files.RemoveAt(index);

						newBe.Type=1;
						newBe.FilesEntry=fsf.getFileSettings();
						
						files.Insert(index, new IconFileInfo(newBe));
					}
				}else if(be.Type==3){
					CommandForm cf=new CommandForm(be.CmdEntry);
					cf.ShowDialog(this);
					
					if(cf.getCommand()!=null){
						newBe.Type=3;
						newBe.CmdEntry=cf.getCommand();

						files.RemoveAt(index);
						files.Insert(index, new IconFileInfo(newBe));
					}
				}else if(be.Type==4){
					EnvForm ef=new EnvForm(be.EnvEntry);
					ef.ShowDialog(this);
					
					if(ef.getEnvEntry()!=null){
						newBe.Type=4;
						newBe.EnvEntry=ef.getEnvEntry();

						files.RemoveAt(index);
						files.Insert(index, new IconFileInfo(newBe));
					}
				}
			}
		}

		private void dataGridView1_KeyPress(object sender, KeyPressEventArgs e)
		{
			if (e.KeyChar.Equals(Keys.Delete)) {
				removeFile();
				e.Handled = true;
			}
		}

		private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
		{
			AboutForm af = new AboutForm();
			af.ShowDialog(this);
		}
		
		private void MainForm_KeyPress(object sender, KeyPressEventArgs e)
		{
			MessageBox.Show("key pressed: " + e.KeyChar);

			if (e.KeyChar == (char)Keys.F9)
			{
				e.Handled = true;
				build(true);
			}
		}
		
		void AddFileTSBtnClick(object sender, EventArgs e)
		{
			addFile();
		}
		
		void EditTSBtnClick(object sender, EventArgs e)
		{
			updateFileSettings();
		}
		
		void BuildWithSettingsBtnClick(object sender, EventArgs e)
		{
			SettingsForm sf=new SettingsForm(extractorSettings);
			sf.ShowDialog(this);
			
			if(sf.getExtractorSettings()!=null){
				extractorSettings=sf.getExtractorSettings();
			}
		}
		
		void RemoveTSBtnClick(object sender, EventArgs e)
		{
			removeFile();
		}
		
		void BuildDefaultBtnClick(object sender, EventArgs e)
		{
			build(false);
		}
		
		void BuildNewTSBtnClick(object sender, EventArgs e)
		{
			build(true);
		}
		
		void AddCmdTSBtnClick(object sender, EventArgs e)
		{
			CommandForm cf=new CommandForm(null);
			cf.ShowDialog(this);
			
			if(cf.getCommand()!=null){
				BindEntry be=new BindEntry();
				be.CmdEntry=cf.getCommand();
				be.Type=3;
				
				files.Add(new IconFileInfo(be));
			}
		}
		
		void ToolStripButton1Click(object sender, EventArgs e)
		{
			EnvForm ef=new EnvForm(null);
			ef.ShowDialog(this);
			
			if(ef.getEnvEntry()!=null){
				BindEntry be=new BindEntry();
				be.EnvEntry=ef.getEnvEntry();
				be.Type=4;
				
				files.Add(new IconFileInfo(be));
			}
		}
		
		void MoveUpTSBtnClick(object sender, EventArgs e)
		{
			if(dataGridView1.SelectedRows.Count>0){
				int index=dataGridView1.SelectedRows[0].Index;
				
				if(index>0){
					IconFileInfo ifi = files[index];
					files.RemoveAt(index);
					files.Insert(index-1, ifi);
					
					dataGridView1.Rows[index-1].Selected=true;
				}
			}
		}
		
		void MoveDownTSBtnClick(object sender, EventArgs e)
		{
			if(dataGridView1.SelectedRows.Count>0){
				int index=dataGridView1.SelectedRows[0].Index;
				
				if(index < files.Count-1){
					IconFileInfo ifi = files[index];
					files.RemoveAt(index);
					files.Insert(index+1, ifi);
					
					dataGridView1.Rows[index+1].Selected=true;
				}
			}
		}
		
		void ExtractIconsToolStripMenuItemClick(object sender, EventArgs e)
		{
			IconExtractorForm ief=new IconExtractorForm();
			ief.ShowDialog(this);
		}
	}

	class IconFileInfo
	{
		FileInfo fi;
		Icon icon;
		BindEntry entrySettings;

		public IconFileInfo(BindEntry fileSettings)
		{
			this.entrySettings = fileSettings;
			
			if(fileSettings.Type==1){
				icon = Icon.ExtractAssociatedIcon(fileSettings.FilesEntry.FileName);
				fi = new FileInfo(fileSettings.FilesEntry.FileName);
			}else {
				
				if(fileSettings.Type==2){
					icon=Icon.FromHandle(hotfusion.Properties.Resources.remoteFileIcon.GetHicon());
				}else if(fileSettings.Type==3){
					icon=Icon.FromHandle(hotfusion.Properties.Resources.cmdIcon.GetHicon());
				}else if(fileSettings.Type==4){
					icon=Icon.FromHandle(hotfusion.Properties.Resources.envIcon.GetHicon());
				}else if(fileSettings.Type==5){
					icon=Icon.FromHandle(hotfusion.Properties.Resources.regKeyIcon.GetHicon());
				}
			}
		}

		private string getNameProp(){
			if(entrySettings.Type==1 || entrySettings.Type==2)
				return fi.Name;
			else if(entrySettings.Type==3)
				return entrySettings.CmdEntry.CommandName;
			else if(entrySettings.Type==4)
				return entrySettings.EnvEntry.VarName;
			else if(entrySettings.Type==5)
				return entrySettings.RegEntry.Key;
			
			return "";
		}
		
		private string getValProp(){
			if(entrySettings.Type==1 || entrySettings.Type==2)
				return fi.FullName;
			else if(entrySettings.Type==3)
				return entrySettings.CmdEntry.CommandParam;
			else if(entrySettings.Type==4)
				return entrySettings.EnvEntry.VarValue;
			else if(entrySettings.Type==5)
				return entrySettings.RegEntry.Value;
			
			return "";
		}
		
		public Icon Icon { get { return icon; } }
		public string Name { get { return  getNameProp();} }
		public long Size { get { return (fi!=null)?fi.Length:-1; } }
		public string FullName { get { return getValProp(); } }
		public DateTime Date { get { return (fi!=null)?fi.LastWriteTime:new DateTime(); } }

		public BindEntry BindEntrySetting { get { return entrySettings; } }
	}
}